package com.liveinstars.gateway.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.liveinstars.api.dto.Sign;
import com.liveinstars.gateway.business.entity.AuthSecretDTO;
import com.liveinstars.gateway.business.entity.ChangeSecretKeyDTO;
import com.liveinstars.gateway.business.repository.facade.AuthSecretManager;
import com.liveinstars.gateway.business.service.AppAuthService;
import com.liveinstars.gateway.business.service.AuthService;
import com.onepiece.shipelves.common.exception.AuthException;
import com.onepiece.shipelves.common.utils.AESPKCS7Util;
import com.onepiece.shipelves.common.utils.RSAUtil;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Random;

/**
 * @author: ting
 * @date: 2019-08-05
 */
@Service("appAuthService")
public class AppAuthServiceImpl implements AuthService, AppAuthService {

    private final static Logger logger = LoggerFactory.getLogger(AppAuthServiceImpl.class);

    private static final Long INVALID_SECOND = 1800L;

    private static final Long APP_APP_ID = 0L;

    @Autowired
    private AuthSecretManager authSecretManager;

    /**
     * 验证客户端签名有效，非jwt
     * @param signStr
     * @param version
     * @return
     * @throws Exception
     */
    @Override
    public boolean validateSign(String signStr, Integer version) throws Exception {
        AuthSecretDTO newAuthSecret = authSecretManager.getNewAuthSecret(0L, 1);
        String msg = RSAUtil.decode(signStr, newAuthSecret.getSecretKeyDTO().getPrivateSecretKey());
        if (! StringUtils.isEmpty(msg)) {
            Sign sign = JSON.parseObject(msg, Sign.class);
            long passTime = (System.currentTimeMillis() / 1000) - sign.getTimestamp();
            if (sign.getAppId().equals(APP_APP_ID) && passTime < INVALID_SECOND) {
                return true;
            } else {
                return false;
            }
        } else {
            throw new AuthException("202", "签名失效");
        }
    }

    @Override
    public AuthSecretDTO getByAppIdAndType(Long appId, Integer version) {
        AuthSecretDTO authSecret = authSecretManager.getByAppIdVersionAndType(appId, version, 1);
        return authSecret;
    }

    @Override
    public AuthSecretDTO getNewAuthSecret(Long appId) {
        AuthSecretDTO newAuthSecret = authSecretManager.getNewAuthSecret(appId, 1);
        return newAuthSecret;
    }

    @Override
    public Boolean needChangeSecretKey(Long appId, Integer version) {
        AuthSecretDTO newAuthSecret = authSecretManager.getNewAuthSecret(appId, 1);
        if (newAuthSecret.getVersion() > version) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public String changeSecretKey(ChangeSecretKeyDTO changeSecretKeyDTO) throws AuthException {
        String decode = null;
        AuthSecretDTO authSecretDTO = null;
        try {
            logger.info("changeSecretKey {}", changeSecretKeyDTO);
            authSecretDTO = authSecretManager.getByAppIdVersionAndType(changeSecretKeyDTO.getAppId(), changeSecretKeyDTO.getSecretKeyVersion(), 1);
            logger.info("changeSecretKey authsecret {}", authSecretDTO);
            String magicKey = RSAUtil.decode(changeSecretKeyDTO.getMagicKey(), authSecretDTO.getSecretKeyDTO().getPrivateSecretKey());
            logger.info("changeSecretKey magice {}", magicKey);
            decode = AESPKCS7Util.decrypt(changeSecretKeyDTO.getMsg(), magicKey);
            logger.info("changeSecretKey decode {}", decode);
        } catch (Exception e) {
            logger.error("更变公钥异常：appId:{}, version:{}, sign:{}", changeSecretKeyDTO.getAppId(), changeSecretKeyDTO.getSecretKeyVersion(), changeSecretKeyDTO.getMsg(), e);
            throw new AuthException("401", "旧公钥存在异常");
        }
        if (! StringUtils.isEmpty(decode)) {
            ChangeSecretKeyDTO dto = JSON.parseObject(JSON.parse(decode).toString(),ChangeSecretKeyDTO.class);
            if (dto.check(authSecretDTO)) {
                AuthSecretDTO newAuthSecret = authSecretManager.getNewAuthSecret(changeSecretKeyDTO.getAppId(), 1);
                logger.info("changeSecretKey newaauthsecret {}", newAuthSecret);
                ChangeSecretKeyDTO newChangeSecretKeyDTO = new ChangeSecretKeyDTO();
                newChangeSecretKeyDTO.copyFromAuthSecretDTO(newAuthSecret);
                logger.info("changeSecretKey newchange {}", newChangeSecretKeyDTO);
                String magicStr = RandomStringUtils.randomAlphanumeric(16);
                String msg = AESPKCS7Util.encrypt(JSON.toJSONString(newChangeSecretKeyDTO), magicStr);
                String magicKey = RSAUtil.encodePrivate(magicStr, authSecretDTO.getSecretKeyDTO().getPrivateSecretKey());
                return msg + "," + magicKey;
            } else {
                logger.error("更变公钥异常：appId:{}, version:{}, sign:{}", changeSecretKeyDTO.getAppId(), changeSecretKeyDTO.getSecretKeyVersion(), changeSecretKeyDTO.getMsg());
                throw new AuthException("401", "旧公钥存在异常");
            }
        } else {
            logger.error("更变公钥异常：appId:{}, version:{}, sign:{}", changeSecretKeyDTO.getAppId(), changeSecretKeyDTO.getSecretKeyVersion(), changeSecretKeyDTO.getMsg());
            throw new AuthException("401", "旧公钥存在异常");
        }
    }

    public static String getRandomString(int length){
        String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer sb=new StringBuffer();
        for(int i=0;i<length;i++){
            int number=random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }
}
